﻿Imports System.ServiceModel.Configuration
Imports System.Configuration
Imports System.ServiceModel
Imports System.Xml
Imports System.IO
Imports System.Net
Imports System.Security.Cryptography

Public Class NetClientContentDispatcher
    Inherits MysteryEncryptedClient
    Implements IContentDispatcher, IGlobalContentCreator


    Private _content_type_map As New Dictionary(Of String, IContentXml)
    Private _type_map As New Dictionary(Of Type, IContentXml)
    Private _type_name_map As New Dictionary(Of Type, String)

    Private _cache As New Dictionary(Of Guid, IContent)

    Private _lock As New Object

    Private _dispatcher As New MysteryDispacther


    Public Sub New()
        MyBase.New("NetContentDispatcherEndpoint", Nothing)

        For Each Type As Type In getMystery.AssemblyRegister.getTypesMarkedWith(Of ContentType)()
            Dim attr As ContentType = getMystery.AssemblyRegister.getMysteryClassAttribute(Of ContentType)(Type)
            _content_type_map(attr.name) = Type.getMysteryAttribute(Of ContentXmlAttr)().getXmler
            _type_map(Type) = _content_type_map(attr.name)
            _type_name_map(Type) = attr.name
        Next

        Dim noti As NetClientNotificationReceiver = getGlobalObject(Of NetClientNotificationReceiver)()
        AddHandler noti.contentAdded, AddressOf Me.contentAddedHandler
        AddHandler noti.contentRemoved, AddressOf Me.contentRemovedHandler
        AddHandler noti.contentEdit, AddressOf Me.contentEditHandler

    End Sub

    Public Sub addContents(contents As System.Collections.Generic.IEnumerable(Of IContent)) Implements IContentContainer.addContents
        For Each c As IContent In contents
            Me.Add(c)
        Next
    End Sub

    Public Function containsType(Of T As IContent)() As Boolean Implements IContentContainer.containsType
        Dim message As New containsTypeInput With {.content_type_name = _type_name_map(GetType(T))}
        Dim result As containsTypeOutPut = EcriptSendAndDescriptAnswer(message)
        Return result.it_does
    End Function


    Public Function getAll(Of T As IContent)() As System.Collections.Generic.IEnumerable(Of T) Implements IContentContainer.getAll
        Dim message As New getAllByTypeInput With {.content_type_name = _type_name_map(GetType(T))}

        Dim answer As getAllByTypeOutPut = EcriptSendAndDescriptAnswer(message)
        If answer Is Nothing Then Return New List(Of T)(0)

        Dim guids As New List(Of String)(answer.guids)

        Dim result As New List(Of T)(guids.Count)
        For Each guid_s As String In guids
            result.Add(Me.getContent(Of T)(Guid.Parse(guid_s)))
        Next
        Return result
    End Function

    

    Public Function getAllByFilter(Of T As IContent)(filter As T) As System.Collections.Generic.IEnumerable(Of T) Implements IContentContainer.getAllByFilter
        Dim message As New getAllByFilterInput
        If filter IsNot Nothing Then
            Dim type As Type = filter.GetType
            Dim xmler As IContentXml = _type_map(type)
            message.doc = xmler.generateAsFilter(filter).InnerXml
        End If

        Dim output As getAllByFilterOutPut = EcriptSendAndDescriptAnswer(message)

        Dim result As New List(Of T)(output.docs.Count)
        For Each doc_s As String In output.docs
            Dim doc As New XmlDocument
            doc.InnerXml = doc_s
            Dim xmlelement As XmlElement = doc.FirstChild
            Dim content_type_name As String = xmlelement.Name
            result.Add(_content_type_map(content_type_name).read(doc))
        Next
        Return result
    End Function

    Public Function getContent(Of T As IContent)(guid As System.Guid) As T Implements IContentContainer.getContent
        If _cache.ContainsKey(guid) Then Return _cache(guid)
        Dim net_result As getContentOutPut = EcriptSendAndDescriptAnswer(New getContentInput With {.guid = guid.ToString})
        Dim doc As New XmlDocument
        doc.InnerXml = net_result.doc
        Dim xmlelement As XmlElement = doc.FirstChild
        Dim content_type_name As String = xmlelement.Name
        Dim result As IContent = _content_type_map(content_type_name).read(doc)
        _cache(guid) = result
        Return result
    End Function

    Public Function getAllTheContents() As System.Collections.Generic.IEnumerable(Of IContent) Implements IContentRetriver.getAllTheContents
        Throw New Exception("kind of impossible bro")
    End Function

    Public Sub Add(item As IContent) Implements System.Collections.Generic.ICollection(Of IContent).Add
        If item Is Nothing Then Exit Sub
        Dim message As New addContentInput
        Dim type As Type = item.GetType
        Dim xmler As IContentXml = _type_map(type)
        message.doc = xmler.generate(item).InnerXml
        EcriptSendAndDescriptAnswer(message)
        _cache.Remove(item.guid)
    End Sub

    Public Sub Clear() Implements System.Collections.Generic.ICollection(Of IContent).Clear
        'nothing to do here
    End Sub

    Public Function Contains(item As IContent) As Boolean Implements System.Collections.Generic.ICollection(Of IContent).Contains
        Return Me.getContent(Of IContent)(item.guid) IsNot Nothing
    End Function

    Public Sub CopyTo(array() As IContent, arrayIndex As Integer) Implements System.Collections.Generic.ICollection(Of IContent).CopyTo
        Exit Sub
    End Sub

    Public ReadOnly Property Count As Integer Implements System.Collections.Generic.ICollection(Of IContent).Count
        Get
            Return 0
        End Get
    End Property

    Public ReadOnly Property IsReadOnly As Boolean Implements System.Collections.Generic.ICollection(Of IContent).IsReadOnly
        Get
            Return False
        End Get
    End Property

    Public Function Remove(item As IContent) As Boolean Implements System.Collections.Generic.ICollection(Of IContent).Remove
        Dim message As New removeContentInput With {.guid = item.guid.ToString}
        EcriptSendAndDescriptAnswer(message)
        Return True
    End Function

    Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of IContent) Implements System.Collections.Generic.IEnumerable(Of IContent).GetEnumerator
        Throw New Exception("neeeeeeeee")
    End Function

    Public Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
        Throw New Exception("neeeeeeeee")
    End Function


    Public Event contentAdded(content As IContent) Implements IContentContainer.contentAdded

    Public Event contentChanged() Implements IContentContainer.contentChanged

    Public Event contentRemoved(content As IContent) Implements IContentContainer.contentRemoved

    Private Sub contentAddedHandler(c_guid As Guid)
        _cache.Remove(c_guid)
        RaiseEvent contentAdded(getContent(Of IContent)(c_guid))
    End Sub

    Private Sub contentRemovedHandler(content As IContent)
        RaiseEvent contentRemoved(content)
    End Sub

    Public Event contentEdit(content As IContent) Implements IContentDispatcher.contentEdit

    Private Sub contentEditHandler(content As IContent)
        _cache.Remove(content.guid)
        RaiseEvent contentEdit(content)
        getGlobalObject(Of ContentModifications).notificate(content)
    End Sub

    Public Function getNewContent(type As System.Type) As IContent Implements IGlobalContentCreator.getNewContent
        Dim message As New createContentInput With {.content_type_name = _type_name_map(type)}
        Dim net_result As createContentOutput = EcriptSendAndDescriptAnswer(message)
        Dim doc As New XmlDocument
        doc.InnerXml = net_result.doc
        Dim result As IContent = _type_map(type).read(doc)
        Return result
    End Function

    Public Function getNewContent1(Of T As IContent)() As T Implements IGlobalContentCreator.getNewContent
        Return Me.getNewContent(GetType(T))
    End Function

    Public Function getLightContentRereferece(Of T As IContent)() As System.Collections.Generic.IEnumerable(Of LightContentReferece) Implements IContentContainer.getLightContentRereferece
        Dim message As New getLightReferenceInput With {.content_type_name = _type_name_map(GetType(T))}
        Dim net_result As getLightReferenceOutput = EcriptSendAndDescriptAnswer(message)
        Return net_result.references
    End Function

    Public Event retrivingFile(file_content As FileContent, pieces As Integer)
    Public Event pieceRetrived(file_content As FileContent, pieces As Integer)
    Public Event fileRetrived(file_content As FileContent)

    Private get_file_lock As New Object


    Public Function getFile(file_content As FileContent) As System.IO.FileInfo Implements IContentDispatcher.getFile

        Try
            Dim root As DirectoryInfo = getGlobalObject(Of MysteryConfiguration).files_root_folder
            Dim this_path As String = Path.Combine(root.FullName, file_content.location.value)
            If File.Exists(this_path) Then
                Return New FileInfo(this_path)
            End If

            Dim splites() As String = file_content.location.value.Split(Path.DirectorySeparatorChar)

            Dim y As String = splites(0)
            Dim m As String = splites(1)

            Dim full_path As String = Path.Combine(root.FullName, y)
            If Not Directory.Exists(full_path) Then
                root.CreateSubdirectory(y)
            End If

            root = New DirectoryInfo(full_path)

            full_path = Path.Combine(full_path, m)
            If Not Directory.Exists(full_path) Then
                root.CreateSubdirectory(m)
            End If

            root = New DirectoryInfo(full_path)
            full_path = Path.Combine(full_path, splites(2))

            If Not downloadFromWeb(file_content, full_path) Then
                downloadFromServer(file_content, full_path)
            End If


            RaiseEvent fileRetrived(file_content)
            'Throw New Exception("neeeeeee")
            Return New FileInfo(full_path)
        Catch ex As Exception
            MsgBox(ex.StackTrace, MsgBoxStyle.Information, ex.Message)
            Return Nothing
        End Try
    End Function

    Private Function downloadFromWeb(file_content As FileContent, target_path As String) As Boolean
        If file_content Is Nothing OrElse String.IsNullOrEmpty(file_content.web_position.value) Then Return False
        Try
            Dim sp As HttpWebRequest = HttpWebRequest.Create(file_content.web_position.value)
            Dim respose As HttpWebResponse = sp.GetResponse()
            Dim s As Stream = respose.GetResponseStream
            Dim bytes As New List(Of Byte)
            Do
                Dim b As Integer = s.ReadByte()
                If b = -1 Then Exit Do
                bytes.Add(b)
            Loop
            Dim sw As New FileStream(target_path, FileMode.CreateNew)
            sw.Write(bytes.ToArray, 0, bytes.Count)
            sw.Close()
            Return True
        Catch ex As Exception
            Return False
        End Try

    End Function

    Private Sub downloadFromServer(file_content As FileContent, target_path As String)
        Dim message As New getFileInput With {.guid = file_content.guid.ToString}
        Dim net_result As getFileOutput = EcriptSendAndDescriptAnswer(message)


        RaiseEvent retrivingFile(file_content, net_result.pieces)

        Dim base64 As String = String.Empty
        For i As Integer = 0 To net_result.pieces - 1
            Dim piece_request As New getFilePieceInput With {.buffer_guid = net_result.buffer_guid, .piece = i}
            Dim piece_result As getFilePieceOutput = EcriptSendAndDescriptAnswer(piece_request)
            base64 &= piece_result.buffer_piece
            RaiseEvent pieceRetrived(file_content, i)
        Next

        Try

            Dim sw As New FileStream(target_path, FileMode.CreateNew)
            sw.Write(System.Convert.FromBase64String(base64), 0, net_result.lenght)
            sw.Close()
        Catch ex As Exception

        End Try
    End Sub

    Public Function search(search_text As String) As System.Collections.Generic.IEnumerable(Of IContent) Implements IContentContainer.search
        Dim message As New getSearchResultInput With {.search = search_text}
        Dim net_result As getSearchResultOutput = EcriptSendAndDescriptAnswer(message)
        Dim result As New List(Of IContent)(net_result.guids.Count)
        Dim cd As IContentDispatcher = getGlobalObject(Of IContentDispatcher)()
        For Each guid_s As String In net_result.guids
            result.Add(cd.getContent(Of IContent)(Guid.Parse(guid_s)))
        Next
        Return result
    End Function



End Class
